package io.nutz.nutzsite.module.acm.front;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.binary.Base64;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import org.nutz.plugins.slog.annotation.Slog;

import io.nutz.nutzsite.common.base.Globals;
import io.nutz.nutzsite.common.base.Result;
import io.nutz.nutzsite.common.page.TableDataInfo;
import io.nutz.nutzsite.common.socket.OJSocket;
import io.nutz.nutzsite.common.utils.DateUtils;
import io.nutz.nutzsite.common.utils.ShiroUtils;
import io.nutz.nutzsite.module.acm.models.CompileInfo;
import io.nutz.nutzsite.module.acm.models.Contest;
import io.nutz.nutzsite.module.acm.models.Problem;
import io.nutz.nutzsite.module.acm.models.Solution;
import io.nutz.nutzsite.module.acm.models.SolutionSource;
import io.nutz.nutzsite.module.acm.services.AttendService;
import io.nutz.nutzsite.module.acm.services.CompileInfoService;
import io.nutz.nutzsite.module.acm.services.ContestProblemService;
import io.nutz.nutzsite.module.acm.services.ContestService;
import io.nutz.nutzsite.module.acm.services.ProblemService;
import io.nutz.nutzsite.module.acm.services.SolutionService;
import io.nutz.nutzsite.module.acm.services.SolutionSourceService;
import io.nutz.nutzsite.module.sys.models.User;
import io.nutz.nutzsite.module.sys.services.UserService;


/**
 * acm题目 信息操作处理
 * 
 * @author lrw
 * @date 2020-02-16
 */
@IocBean
@At("/acm/front")
public class ACMFrontController {
	private static final Log log = Logs.get();
	@Inject
	private UserService userService;
	@Inject
	private ProblemService problemService;
	@Inject
	private SolutionService solutionService;
	@Inject
	private SolutionSourceService  solutionSourceService;
	@Inject
	private CompileInfoService compileInfoService;
	@Inject
	private ContestService contestService;
	@Inject
	private AttendService attendService;
	@Inject
	private ContestProblemService contestProblemService;
	
	@RequiresPermissions("acm:front:view")
	@At("")
	@Ok("th:/acm/front/problem.html")
	public void index(HttpServletRequest req) {

	}
	/**
	 * 查询acm题目列表
	 */
	@RequiresPermissions("acm:front:list")
	@At
	@Ok("json")
	public Object list(@Param("pageNum")int pageNum,
					   @Param("pageSize")int pageSize,
					   @Param("problemId") Integer problemId,
					   @Param("title") String title,
					   HttpServletRequest req) {
		Cnd cnd = Cnd.NEW();
		if(problemId!=null){
			cnd.and("problemId", "=", problemId);
		}
		else if (!Strings.isBlank(title)){
			cnd.and("title", "like", "%" + title +"%");
		}

		return problemService.tableList(pageNum,pageSize,cnd,null,null,null);
	}
	@RequiresPermissions("acm:front:list")
	@At
	@Ok("json")
	public Object listAC(@Param("pageNum")int pageNum,
					   @Param("pageSize")int pageSize,
					   @Param("problemId") Integer problemId,
					   @Param("title") String title,
					   HttpServletRequest req) {
		Cnd cnd = Cnd.NEW();
		if(problemId!=null){
			cnd.and("problemId", "=", problemId);
		}
		else if (!Strings.isBlank(title)){
			cnd.and("title", "like", "%" + title +"%");
		}

		return problemService.tableList(pageNum,pageSize,cnd,null,null,null);
	}
	/**
	 * 显示解题信息表，可能是问题集中AC题数跳转过来的
	 * @param problemId
	 * @param verdict
	 * @param req
	 */
	@RequiresPermissions("acm:front:view")
	@At("/status")
	@Ok("th:/acm/front/solution.html")
	public void status(@Param("problemId") Integer problemId,
			@Param("contestId") Integer contestId,
			   @Param("verdict") int verdict,
			   HttpServletRequest req) {
		req.setAttribute("problemId", problemId);
		req.setAttribute("verdict", verdict);
		if(contestId==null) contestId=0;
		req.setAttribute("contestId", contestId);
		User user = ShiroUtils.getSysUser();
		req.setAttribute("user", user);

	}
	/**
	 * 查询acm solution列表
	 */
	@RequiresPermissions("acm:front:list")
	@At
	@Ok("json")
	public Object listsolution(@Param("pageNum")int pageNum,
					   @Param("pageSize")int pageSize,
					   @Param("problemId") Integer problemId,
					   @Param("contestId") Integer contestId,
					   @Param("uid") String uid,
					   @Param("ksid") String ksid,
					   @Param("verdict") int verdict,
					   @Param("orderByColumn") String orderByColumn,
					   @Param("isAsc") String isAsc,
					   HttpServletRequest req) {
		Cnd cnd = Cnd.NEW();
		if(problemId!=null){
			cnd.and("problemId", "=", problemId);
		}
		if(contestId==null) contestId=0;
		cnd.and("contestId", "=", contestId);
		if (!Strings.isBlank(ksid)){
			cnd.and("ksid", "=", ksid);
		}
		if (!Strings.isBlank(uid)){
			cnd.and("uid", "=", uid);
		}
		if (verdict>1){
			cnd.and("verdict", "=", verdict);
		}
		/*return solutionService.tableList(pageNum,pageSize,cnd,orderByColumn,isAsc,"problem");*/
		TableDataInfo tableDataInfo=solutionService.tableList(pageNum,pageSize,cnd,orderByColumn,isAsc,null);
		List<Solution> list=(List<Solution>) tableDataInfo.getRows();
		//int n=0;
		//if(list!=null) n= list.size();
		for(Solution sol : list){
			Problem problem=problemService.fetch(((Solution)sol).getProblemId());
			sol.setTitle(problem.getTitle());
		}
		return new TableDataInfo(list, (int) tableDataInfo.getTotal());
	}
	/**
	 * 等待状态变化的部分id对应的solution
	 */
	@At
	@Ok("json")
	public Object partsolution(@Param("ids")String ids,
					   HttpServletRequest req) {
		Cnd cnd = Cnd.NEW();
		cnd.and("solutionId", "in", ids.split(","));
		return solutionService.query(cnd);
	}
	/**
	 * 
	 * @param ids
	 * @param req
	 * @return
	 */
	@At
	@Ok("json")
	public Object examsolution(@Param("ids")String ids,@Param("ksid")String ksid,
					   HttpServletRequest req) {		
		List<Solution> sols=new ArrayList<Solution>();
		String[] idarr=ids.split(",");
		for(int i=0;i<idarr.length;i++)
		{
			Cnd cnd = Cnd.NEW();
			cnd.and("ksid","=",ksid);
			cnd.and("problemId", "=",idarr[i] );
			cnd.and("uid","=",ShiroUtils.getSysUserId());
			cnd.desc("solutionId");
			Solution sol=solutionService.fetch(cnd);
			if(sol!=null) sols.add(sol);
		}		
		return sols;
	}
	@RequiresPermissions("acm:front:view")
	@At
	@Ok("th:/acm/front/rank.html")
	public void rank(HttpServletRequest req) {

	}
	@RequiresPermissions("acm:front:list")
    @At
    @Ok("json")
    public Object listrank(@Param("pageNum")Integer pageNum,
                       @Param("pageSize")Integer pageSize,
                       @Param("orderByColumn") String orderByColumn,
                       @Param("classg") String classg,
                       @Param("isAsc") String isAsc,
                       HttpServletRequest req) {
		Cnd cnd = Cnd.NEW();
		if(!Strings.isBlank(classg)) cnd.and("classg","like","%"+classg+"%");
		cnd.and("submit",">",0);
        return userService.tableList(pageNum, pageSize, cnd, orderByColumn, isAsc, null);
    }	
    @At
    @Ok("json")
    public Object listrank2(@Param("pageNum")Integer pageNum,
                       @Param("pageSize")Integer pageSize,
                       @Param("orderByColumn") String orderByColumn,
                       //@Param("classg") String classg,
                       @Param("isAsc") String isAsc,
                       HttpServletRequest req) {
		Cnd cnd = Cnd.NEW();
		User user = ShiroUtils.getSysUser();
		String classg=user.getClassg();
		if(!Strings.isBlank(classg)) cnd.and("classg","=",classg);
		cnd.and("submit",">",0);
        return userService.tableList(pageNum, pageSize, cnd, orderByColumn, isAsc, null);
    }
	/**
	 * 查询编译错误信息
	 */
	@At
	@Ok("json")
	public Result ce(@Param("solutionId") int solutionId, HttpServletRequest req) {
		CompileInfo compileInfo=compileInfoService.fetch(solutionId);
		String ceinfo="<pre>"+compileInfo.getError()+"</pre>";
		return Result.success(ceinfo);
	}
	/**
	 * 查询编译错误信息
	 */
	@At
	@Ok("raw:html")
	public Object ce2(@Param("solutionId") int solutionId, HttpServletRequest req) {
		CompileInfo compileInfo=compileInfoService.fetch(solutionId);
		String ceinfo=compileInfo.getError();
		int s1=ceinfo.indexOf(":");
		ceinfo=ceinfo.substring(s1+1);
		ceinfo="<pre><code>"+ceinfo.replace(">", "&gt;").replace("<", "&lt;")+"</code></pre>";
		return ceinfo;
	}
	/**
	 * 查询编译错误信息
	 */
	@At
	@Ok("th:/hljscode.html")
	public void ce3(@Param("solutionId") int solutionId, HttpServletRequest req) {
		CompileInfo compileInfo=compileInfoService.fetch(solutionId);
		String ceinfo=compileInfo.getError();
		int s1=ceinfo.indexOf(":");
		ceinfo=ceinfo.substring(s1+1);
		ceinfo=ceinfo.replace(">", "&gt;").replace("<", "&lt;");
		req.setAttribute("code", ceinfo);
	}
	/**
	 * 查询源代码信息
	 */
	@At
	@Ok("th:/hljscode.html")
	public void src(@Param("solutionId") int solutionId, HttpServletRequest req) {
		SolutionSource solutionSource=solutionSourceService.fetch(solutionId);
		String ceinfo=solutionSource.getSource();
		ceinfo=ceinfo.replace(">", "&gt;").replace("<", "&lt;");
		req.setAttribute("code", ceinfo);
	}
	/**
	 * 新增保存acm题目
	 */
	@At
	@POST
	@Ok("json")
	@RequiresPermissions("acm:front:add")
	@Slog(tag="acm题目", after="新增保存acm题目 id=${args[0].id}")
	public Object addDo(@Param("..") Problem problem,HttpServletRequest req) {
		try {
			problemService.insert(problem);
			return Result.success("system.success");
		} catch (Exception e) {
			return Result.error("system.error");
		}
	}

	/**
	 * 显示acm题目
	 */
	@RequiresPermissions("acm:front:detail")
	@At("/detail")
	@Ok("th://acm/front/detail.html")
	public void detail(@Param("problemId")String id, @Param("contestId")Integer contestId,HttpServletRequest req) {
		Problem problem = problemService.fetch(Integer.parseInt(id));
		req.setAttribute("problem",problem);
		if(contestId==null) contestId=0;
		req.setAttribute("contestId",contestId);
	}

	/**
	 * 保存提交的源码
	 */
	@At
	@POST
	@Ok("json")
	@RequiresPermissions("acm:front:submit")
	@Slog(tag="提交源码", after="保存提交的源码")
	public Object submitCode(@Param("..") Solution sol,@Param("source") String source,HttpServletRequest req) {
		try {
			if(Lang.isNotEmpty(sol)){
				Date dt_prevSubmit = (Date)Mvcs.getHttpSession().getAttribute("session_submit");
				Date dt = new Date(); 
				User user = ShiroUtils.getSysUser();
				if(dt_prevSubmit!=null){
					if(dt.getTime()-dt_prevSubmit.getTime()<5000){
						return Result.success(user.getId()+",系统不允许在5秒内再次提交代码");
					}
				}
				
				Base64 base64 = new Base64();
				String source2=new String(base64.decode(source), "UTF-8");
				
				sol.setUid(user.getId());				
				sol.setCodeLength(source2.length());
				sol.setSubmitDate(new Date());
				sol.setMemory(0);
				sol.setTime(0);
				//sol.setContestId("0");
				sol.setTestcase(0);
				sol.setVerdict(1);

				Solution s=solutionService.insert(sol);
				SolutionSource ss=new SolutionSource();
				ss.setSolutionId(s.getSolutionId());				
				ss.setSource(source2);
				solutionSourceService.insert(ss);
				
				Mvcs.getHttpSession().setAttribute("session_submit", dt);
				//========================================================
				String judger_ip =Globals.getConfig("OJ_JUDGER_IP");
				Integer judger_port = Integer.valueOf(Globals.getConfig("OJ_JUDGER_PORT")).intValue();
				OJSocket.JudgeRequest(judger_ip, judger_port, s.getSolutionId());
			}
			return Result.success("");
		} catch (Exception e) {
			return Result.error(e.getMessage());
		}
	}

	/**
	 * 删除acm题目
	 */
	@At("/remove")
	@Ok("json")
	@RequiresPermissions("acm:front:remove")
	@Slog(tag ="acm题目", after= "删除acm题目:${array2str(args[0])}")
	public Object remove(@Param("ids")String[] ids, HttpServletRequest req) {
		try {
			problemService.delete(ids);
			return Result.success("system.success");
		} catch (Exception e) {
			return Result.error("system.error");
		}
	}
	
	@RequiresPermissions("acm:front:contest")
	@At
	@Ok("th:/acm/front/contest.html")
	public void contest(HttpServletRequest req) {
		req.setAttribute("now0", DateUtils.getDateTime());
	}
	/**
	 * 查询ACM竞赛列表
	 */
	@RequiresPermissions("acm:front:clist")
	@At
	@Ok("json")
	public Object clist(@Param("pageNum")int pageNum,
					   @Param("pageSize")int pageSize,
					   HttpServletRequest req) {
		Cnd cnd = Cnd.NEW();
		return contestService.tableList(pageNum,pageSize,cnd,"startTime","desc",null);
	}
	
	@At
	@Ok("th:/acm/front/contestProblem.html")
	public void contestP(@Param("cid")Integer cid,HttpServletRequest req) {
		Contest contest=contestService.fetch(cid);
        req.setAttribute("contest", contest);
        req.setAttribute("now0", DateUtils.getDateTime());
        req.setAttribute("maxtime", DateUtils.isInTime(contest.getStartReg(), contest.getEndReg()));
	}
	@At
	@Ok("th:/acm/front/rankio.html")
	public void rankio(@Param("cid")Integer cid,HttpServletRequest req) {
		try {

			//Cnd cnd = Cnd.NEW();
			//List<Attend> attends=attendService.query(cnd.and("contestId","=",cid).desc("solved"));
			//req.setAttribute("rank", attends);
			int n=contestProblemService.count(Cnd.where("contestId","=",cid));
			req.setAttribute("cpnum", n);
			Contest contest=contestService.fetch(cid);
	        req.setAttribute("contest", contest);
	        req.setAttribute("now0", DateUtils.getDateTime());
	        req.setAttribute("maxtime", DateUtils.isInTime(contest.getStartReg(), contest.getEndReg()));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
